package com.tbit.uqbike.webmanager.business.machine_op_log.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.MachineOpLog;
import com.tbit.common.entity.UserOpLog;
import com.tbit.common.utils.TraceUtil;
import com.tbit.config.datasource.DataSource;
import com.tbit.uqbike.object.business.UserInfo;
import com.tbit.uqbike.object.pojo.Machine;
import com.tbit.common.entity.view.PageResult;
import com.tbit.uqbike.webmanager.business.machine_op_log.dao.log.MachineOpLogDao;
import com.tbit.uqbike.webmanager.business.machine_op_log.object.dto.MachineOpLogPageReq;
import com.tbit.uqbike.webmanager.business.user_op_log.service.UserOpLogService;
import com.tbit.uqbike.webmanager.controller.BaseController;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.tbit.common.entity.MachineOpLog.Fields;

/**
 * @author <a href="mailto:zheng.zebiao@tbit.com.cn">zb</a>
 * @since 2024/11/18
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MachineOpLogService extends ServiceImpl<MachineOpLogDao, MachineOpLog> {
    final UserOpLogService userOpLogService;
    final AccountDao accountDao;

    private static ThreadLocal<Integer> brandIdThreadLocal = new ThreadLocal<>();

    public PageResult<MachineOpLog> getRecordList(MachineOpLogPageReq req) {
        Integer brandId = brandIdThreadLocal.get();
        if (Objects.isNull(brandId)) {
            brandId = accountDao.getBrandIdByAccountIdV2(req.getAccountId());
        }
        brandIdThreadLocal.remove();
        QueryWrapper<MachineOpLog> queryWrapper = Wrappers.query(MachineOpLog.class)
                .in(Fields.accountId, req.getAccountId(), brandId)
                .eq(req.getMachineNO() != null, Fields.machineNO, req.getMachineNO())
                .eq(req.getUserCode() != null, Fields.userCode, req.getUserCode())
                .eq(req.getOpPlatform() != null, Fields.opPlatform, req.getOpPlatform())
                .eq(req.getOperation() != null, Fields.operation, req.getOperation())
                .eq(req.getOpUserPhone() != null, Fields.opUserPhone, req.getOpUserPhone())
                .between(req.getStartTime() != null && req.getEndTime() != null, Fields.opTime, req.getStartTime(), req.getEndTime())
                .orderByDesc(Fields.opTime);

        return PageResult.convertPage(
                getBaseMapper().selectPage(Page.of(req.getPageNO(), req.getRowCount()), queryWrapper)
        );
    }

    /**
     * 批量添加日志，自动填充操作人
     *
     * @param machineInfos 车辆信息
     */
    @DS(DataSource.LOG)
    public void batchAddRecord(String operation, String opType, Boolean result, String detail, List<Machine> machineInfos) {
        if (CollUtil.isEmpty(machineInfos)) {
            return;
        }
        StringBuilder sb = new StringBuilder(ObjectUtil.defaultIfEmpty(detail, ""));
        String traceId = TraceUtil.getTraceIdByLocal();
        if (traceId != null) {
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append("TraceID: ")
                    .append(traceId);
        }
        try {
            UserInfo userInfo = BaseController.fetchUserInfo();

            List<MachineOpLog> opLogs = machineInfos.stream()
                    .map(machine -> MachineOpLog.builder()
                            .accountId(machine.getAccountId())
                            .machineId(machine.getMachineId())
                            .machineNO(machine.getMachineNO())
                            .userCode(machine.getUserCode())
                            .operation(operation)
                            .opType(opType)
                            .opUser(userInfo.getName())
                            .opUserPhone(userInfo.getPhone())
                            .opPlatform(OperationPlatform.MANAGER.code)
                            .opTime(LocalDateTime.now())
                            .result(result)
                            .detail(sb.length() > 0 ? sb.toString() : null)
                            .build())
                    .collect(Collectors.toList());
            saveBatch(opLogs);

            // 顺便插入用户操作日志
            List<UserOpLog> userOpLogs = machineInfos.stream()
                    .map(machine -> UserOpLog.builder()
                            .accountId(machine.getAccountId())
                            .operation(operation)
                            .opType(opType)
                            .opUser(userInfo.getName())
                            .opUserPhone(userInfo.getPhone())
                            .opPlatform(OperationPlatform.MANAGER.code)
                            .opTime(LocalDateTime.now())
                            .result(result)
                            .detail(sb + "车辆编号: " + machine.getUserCode() + "\n中控编号: " + machine.getMachineNO())
                            .build())
                    .collect(Collectors.toList());
            userOpLogService.saveBatch(userOpLogs);
        } catch (Exception e) {
            log.error("[车辆操作日志] 批量添加日志失败，信息: {} {} {} {}", operation, opType, result, detail, e);
        }
    }

    @DS(DataSource.LOG)
    public void insertBatch(List<MachineOpLog> opLogs) {
        if (CollUtil.isEmpty(opLogs)) {
            return;
        }
        try {
            String traceId = TraceUtil.getTraceIdByLocal();
            if (traceId != null) {
                for (MachineOpLog opLog : opLogs) {
                    StringBuilder detail = new StringBuilder(ObjectUtil.defaultIfNull(opLog.getDetail(), ""));
                    if (detail.length() > 0) {
                        detail.append("\n");
                    }
                    detail.append("TraceID: ")
                            .append(traceId);
                    opLog.setDetail(detail.length() > 0 ? detail.toString() : null);
                }
            }
            saveBatch(opLogs);
        } catch (Exception e) {
            log.error("[车辆操作日志] 批量添加日志失败，失败条数: {}", opLogs.size(), e);
        }
    }
    /**
     * @description: 查询数据量
     * @author: mo.shanyong
     * @date: 2025/3/17 15:44
     * @param: re
     */
    public int getCount(MachineOpLogPageReq req){
        Integer brandId = accountDao.getBrandIdByAccountIdV2(req.getAccountId());
        brandIdThreadLocal.set(brandId);
        QueryWrapper<MachineOpLog> queryWrapper = Wrappers.query(MachineOpLog.class)
                .in(Fields.accountId, req.getAccountId(), brandId)
                .eq(req.getMachineNO() != null, Fields.machineNO, req.getMachineNO())
                .eq(req.getUserCode() != null, Fields.userCode, req.getUserCode())
                .eq(req.getOpPlatform() != null, Fields.opPlatform, req.getOpPlatform())
                .eq(req.getOperation() != null, Fields.operation, req.getOperation())
                .eq(req.getOpUserPhone() != null, Fields.opUserPhone, req.getOpUserPhone())
                .between(req.getStartTime() != null && req.getEndTime() != null, Fields.opTime, req.getStartTime(), req.getEndTime())
                .orderByDesc(Fields.opTime);
        Long count = getBaseMapper().selectCount(queryWrapper);
        return Objects.isNull(count) ? 0 : count.intValue();
    }
}
